/* **********************************************************************************
 *
 * Copyright (c) Ascend.NET Project. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Shared Source License
 * for Ascend. A copy of the license can be found in the License.html file
 * at the root of this distribution. If you can not locate the Shared Source License
 * for Ascend, please send an email to ascendlic@<TBD>.
 * By using this source code in any fashion, you are agreeing to be bound by
 * the terms of the Shared Source License for Ascend.NET.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Globalization;
using System.ComponentModel.Design.Serialization;
using Ascend.Resources;

namespace Ascend
{
    /// <summary>
    /// Provides a type converter to convert expandable objects to and from various other representations.
    /// </summary>
    public class BorderConverter : TypeConverter
    {
        /// <summary>
        /// Initializes a new instance of the BorderConverter class.
        /// </summary>
        public BorderConverter()
        {
        }

        /// <summary>
        /// Returns whether this converter can convert an object of the given type to the type of this converter.
        /// </summary>
        /// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
        /// <param name="sourceType">A Type that represents the type that you want to convert from.</param>
        /// <returns>true if sourceType is a String type or a Uri type can be assigned from sourceType; otherwise, false.</returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
            {
                return true;

            }

            return base.CanConvertFrom(context, sourceType);

        }

        /// <summary>
        /// Returns whether this converter can convert the object to the specified type.
        /// </summary>
        /// <remarks>
        /// Use the context parameter to extract additional information about the environment from which this converter is invoked. This parameter can be null, so always check it. Also, properties on the context object can return null.
        /// </remarks>
        /// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
        /// <param name="destinationType">A Type that represents the type you want to convert to.</param>
        /// <returns>true if this converter can perform the conversion; otherwise, false.</returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, System.Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                return true;

            }

            return base.CanConvertTo(context, destinationType);

        }

        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information. 
        /// </summary>
        /// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
        /// <param name="culture">The CultureInfo to use as the current culture.</param>
        /// <param name="value">The Object to convert.</param>
        /// <returns>An Object that represents the converted value.</returns>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            string valueString = value as string;
            if (valueString == null)
            {
                return base.ConvertFrom(context, culture, value);

            }

            valueString = valueString.Trim();
            if (valueString.Length == 0)
            {
                return null;

            }

            if (culture == null)
            {
                culture = CultureInfo.CurrentCulture;

            }

            char separator = culture.TextInfo.ListSeparator[0];
            char[] separatorArray = new char[1] { separator };
            string[] textArray = valueString.Split(separatorArray);
            int[] numberArray = new int[textArray.Length];

            TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
            for (int x = 0; x < numberArray.Length; x++)
            {
                numberArray[x] = (int)converter.ConvertFromString(context, culture, textArray[x]);

            }

            if (numberArray.Length == 4)
            {
                return new Border(numberArray[0], numberArray[1], numberArray[2], numberArray[3]);

            }

            throw new ArgumentException(ResourceText.GetLocalizedString("FailedParseFormatError"));

        }

        /// <summary>
        /// Converts the given value object to the specified type, using the specified context and culture information.
        /// </summary>
        /// <remarks>
        /// <para>The most common types to convert are to and from a string object. This implementation calls ToString on the object if the object is valid and if the destination type is string.</para>
        /// <para>Use the context parameter to extract additional information about the environment from which this converter is invoked. This parameter can be null, so always check it. Also, properties on the context object can return null.</para>
        /// </remarks>
        /// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
        /// <param name="culture">A CultureInfo object. If null is passed, the current culture is assumed.</param>
        /// <param name="value">The Object to convert.</param>
        /// <param name="destinationType">The Type to convert the value parameter to.</param>
        /// <returns>An Object that represents the converted value.</returns>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, System.Type destinationType)
        {
            if (destinationType == null)
            {
                throw new ArgumentNullException("destinationType");

            }

            if (value is Border)
            {
                if (destinationType == typeof(string))
                {
                    Border border = (Border)value;

                    if (culture == null)
                    {
                        culture = CultureInfo.CurrentCulture;

                    }

                    string separator = culture.TextInfo.ListSeparator + " ";
                    TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
                    string[] textArray = new string[4];
                    int count = 0;

                    textArray[count++] = converter.ConvertToString(context, culture, border.Left);
                    textArray[count++] = converter.ConvertToString(context, culture, border.Top);
                    textArray[count++] = converter.ConvertToString(context, culture, border.Right);
                    textArray[count++] = converter.ConvertToString(context, culture, border.Bottom);

                    return string.Join(separator, textArray);

                }

                if (destinationType == typeof(InstanceDescriptor))
                {
                    Border border = (Border)value;
                    if (border.ShouldSerializeAll())
                    {
                        Type[] typeArray = new Type[1] { typeof(int) };
                        object[] objectArray = new object[1] { border.All };
                        return new InstanceDescriptor(typeof(Border).GetConstructor(typeArray), objectArray);

                    }

                    Type[] typeArray2 = new Type[4] { typeof(int), typeof(int), typeof(int), typeof(int) };
                    object[] objArray2 = new object[4] { border.Left, border.Top, border.Right, border.Bottom };
                    return new InstanceDescriptor(typeof(Border).GetConstructor(typeArray2), objArray2);

                }

            }

            return base.ConvertTo(context, culture, value, destinationType);

        }

        /// <summary>
        /// Creates an instance of the Type that this TypeConverter is associated with, using the specified context, given a set of property values for the object.
        /// </summary>
        /// <param name="context">An ITypeDescriptorContext that provides a format context.</param>
        /// <param name="propertyValues">An System.Collections.IDictionary of new property values.</param>
        /// <returns>An System.Object representing the given System.Collections.IDictionary, or null if the object cannot be created. This method always returns null.</returns>
        public override System.Object CreateInstance(System.ComponentModel.ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
        {
            if (propertyValues == null)
            {
                throw new ArgumentNullException("propertyValues");

            }

            if (context == null)
            {
                throw new ArgumentNullException("context");

            }


            Border border = (Border)context.PropertyDescriptor.GetValue(context.Instance);
            int numberAll = (int)propertyValues["All"];
            if (border.All != numberAll)
            {
                return new Border(numberAll);

            }

            return new Border((int)propertyValues["Left"], (int)propertyValues["Top"], (int)propertyValues["Right"], (int)propertyValues["Bottom"]);

        }

        /// <param name="context">An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <returns>true if changing a property on this object requires a call to System.ComponentModel.TypeConverter.CreateInstance(System.Collections.IDictionary) to create a new value; otherwise, false.</returns>
        public override System.Boolean GetCreateInstanceSupported(System.ComponentModel.ITypeDescriptorContext context)
        {
            return true;

        }

        /// <summary>
        /// Retrieves the set of properties for this type. By default, a type does not have any properties to return. An easy implementation of this method can call the TypeDescriptor.GetProperties method for the correct data type. 
        /// </summary>
        /// <param name="context">An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <param name="value">The value of the object to get the properties for.</param>
        /// <param name="attributes">An array of MemberAttribute objects that describe the properties.</param>
        /// <returns>A System.ComponentModel.PropertyDescriptorCollection with the properties that are exposed for this data type, or null if there are no properties.</returns>
        public override System.ComponentModel.PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, System.Object value, System.Attribute[] attributes)
        {
            PropertyDescriptorCollection propertyDescriptorCollection = TypeDescriptor.GetProperties(typeof(Border), attributes);
            string[] textArray = new string[5] { "All", "Left", "Top", "Right", "Bottom" };
            return propertyDescriptorCollection.Sort(textArray);

        }

        /// <param name="context">An System.ComponentModel.ITypeDescriptorContext that provides a format context.</param>
        /// <returns>true if System.ComponentModel.TypeConverter.GetProperties(System.Object) should be called to find the properties of this object; otherwise, false.</returns>
        public override System.Boolean GetPropertiesSupported(System.ComponentModel.ITypeDescriptorContext context)
        {
            return true;

        }

    }

}
